package cn.hniu.wechatapp.controller;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.jsoup.Jsoup;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;


import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Controller
public class HelloController {
    private String appId = "56931322";
    private String secret = "o3PgKXTK";

    @Autowired
    RestTemplateBuilder restBuilder;

    @RequestMapping("/poem")
    @ResponseBody
    public String poem(@RequestParam(value = "title", required = false) String title) throws Exception {
        String urlTemplate = "https://so.gushiwen.cn/search.aspx?value=%s&valuej=%s";
        String url = String.format(urlTemplate, title, title.charAt(0)); // 要爬取的网站URL

        org.jsoup.nodes.Document doc = Jsoup.connect(url).get(); // 连接网站并获取HTML文档
        Elements links = doc.select("div.contson"); // 拿到所有诗词数组
        if (links.size() > 0) {
            String content = links.get(0).text(); //诗词
            return content;
        }

        return "";
    }

    @RequestMapping("/hello")
    @ResponseBody
    public String Test() throws Exception {
        RestTemplate restCli = restBuilder.build();
        Map<String, String> reqMap = new HashMap<>();
        reqMap.put("grant_type", "client_credential");
        reqMap.put("appid", "wx57440620655932fa");
        reqMap.put("secret", "f6774c7daed5c65ac259d535acf77a20");

        HttpHeaders reqHeaders = new HttpHeaders();
        reqHeaders.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<Map<String, String>> httpEntity = new HttpEntity<>(reqMap, reqHeaders);


        Object jsonObj = restCli.postForObject("https://api.weixin.qq.com/cgi-bin/stable_token", httpEntity, Object.class);

        ObjectMapper mapper = new ObjectMapper();
        Map<String, Object> jsonData = mapper.readValue(String.valueOf(jsonObj), new TypeReference<Map<String, Object>>() {
        });

        return String.valueOf(jsonData.get("access_token"));
    }

    // 协议://ip地址:端口/接口名称?参数1=参数值1&参数2=参数值2
    // http://localhost:8080/weather?city=株洲
    @RequestMapping("/weather")
    @ResponseBody
    public String weather(@RequestParam(value = "city") String city) throws Exception {
        //1.1 RestTemplate请求对象
        RestTemplate restCli = restBuilder.build();

        HttpHeaders reqHeaders = new HttpHeaders();
        reqHeaders.setContentType(MediaType.APPLICATION_JSON);
        //HttpEntity<Map<String, String>> httpEntity = new HttpEntity<>(reqMap, reqHeaders);

        String urlTemplate = "https://v0.yiketianqi.com/api?unescape=1&version=v91&appid=%s&appsecret=%s&ext=&cityid=&city=%s";

        //1.2 获取天气的json数据
        String jsonStr = restCli.getForObject(String.format(urlTemplate, appId, secret, city), String.class);
        //2.1 解析Json数据
        ObjectMapper mapper = new ObjectMapper();
        Map<String, Object> jsonMap = mapper.readValue(jsonStr, new TypeReference<Map<String, Object>>() {
        });
        List<Object> dataList = (ArrayList<Object>) jsonMap.get("data");
        Map<String, Object> tempMap = (Map<String, Object>) dataList.get(0);
        String temp = String.valueOf(tempMap.get("tem"));
        return city + "当前温度:" + temp;

    }


    @GetMapping("/reply")
    @ResponseBody
    public String WechatReply(@RequestParam(value = "signature", required = false) String signature,
                              @RequestParam(value = "timestamp", required = false) String timestamp,
                              @RequestParam(value = "nonce", required = false) String nonce,
                              @RequestParam("echostr") String echostr) throws Exception {
        System.out.println("signature" + signature);
        System.out.println("timestamp" + timestamp);
        System.out.println("nonce" + timestamp);
        return echostr;
    }

    @PostMapping("/reply")
    public void WechatPostReply(HttpServletRequest request, HttpServletResponse response) throws Exception {
        //1.1 RestTemplate请求对象
        RestTemplate restCli = restBuilder.build();

        HttpHeaders reqHeaders = new HttpHeaders();
        reqHeaders.setContentType(MediaType.APPLICATION_JSON);


        // 将请求、响应的编码均设置为UTF-8（防止中文乱码）
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");

        // 响应消息
        PrintWriter out = response.getWriter();

        String rawData = "";   //对应POST请求的数据

        String msgSignature = request.getParameter("msg_signature"); // 微信加密签名
        String timeStamp = request.getParameter("timestamp");   // 时间戳
        String nonce = request.getParameter("nonce");          // 随机数
        String encryptType = request.getParameter("encrypt_type");

        String cTime = String.valueOf(LocalDateTime.now().atZone(ZoneOffset.UTC).toEpochSecond());

        try {
            // 获取加密的请求消息：使用输入流获得加密请求消息postData
            ServletInputStream in = request.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(in));

            String tempStr = "";   //作为输出字符串的临时串，用于判断是否读取完毕
            while (null != (tempStr = reader.readLine())) {
                rawData += tempStr;
            }


            byte[] contentBytes = rawData.getBytes();
            //byte[] contentBytes = postData.getBytes("UTF-8");
            String postData = new String(contentBytes, StandardCharsets.UTF_8);
            System.out.println("recv content: " + postData);

            // 获取消息明文：对加密的请求消息进行解密获得明文
            if (null != encryptType) {
                System.out.println("safe mode：msg was encrypted");
            } else {
                System.out.println("recive: " + postData);
                Map<String, String> recvMap = parseXml(postData);

                //解析收到的消息
                String from = recvMap.get("FromUserName"); //谁发来的
                String to = recvMap.get("ToUserName"); //发给谁的，这里指公众号
                String content = recvMap.get("Content");
                System.out.println(content);

                //天气北京 天气长沙
                String city = "";

                if (content.length() >= 4 && content.startsWith("天气")) {
                    for (int i = 2; i < content.length(); i++) {
                        city += content.charAt(i);
                    }
                }
                System.out.println("city: " + city);

                //诗词将进酒 诗词静夜思
                String title = "";
                if (content.length() >= 3 && content.startsWith("诗词")) {
                    for (int i = 2; i < content.length(); i++) {
                        title += content.charAt(i);
                    }
                }
                System.out.println("title: " + title);



                //回复天气
                if (!city.equals("")) {
                    System.out.println("weather: " + city);
                    responseWeather(city, restCli, out, to, from, cTime);
                    return;
                }

                //回复诗词
                if (!title.equals("")) {
                    System.out.println("poem: " + title);
                    responsePoem(title, restCli, out, to, from, cTime);
                    return;
                }


                String respMessage = "<xml>\n" +
                        "  <ToUserName><![CDATA[" + from + "]]></ToUserName>\n" +
                        "  <FromUserName><![CDATA[" + to + "]]></FromUserName>\n" +
                        "  <CreateTime>" + cTime + "</CreateTime>\n" +
                        "  <MsgType><![CDATA[text]]></MsgType>\n" +
                        "  <Content><![CDATA[无法识别:" + content + "]]></Content>\n" +
                        "</xml>";

                out.println(respMessage);
            }
        } catch (Exception e) {
            e.printStackTrace();
            out.print("");
            return;
        }


        //空表示暂不回复
        out.print("");

    }

    /**
     * @param title   诗词名称
     * @param restCli
     * @param out
     * @param from
     * @param to
     * @param cTime
     */
    private void responsePoem(String title, RestTemplate restCli, PrintWriter out, String from, String to, String cTime) throws IOException {
        String urlTemplate = "https://so.gushiwen.cn/search.aspx?value=%s&valuej=%s";
        String url = String.format(urlTemplate, title, title.charAt(0)); // 要爬取的网站URL

        org.jsoup.nodes.Document doc = Jsoup.connect(url).get(); // 连接网站并获取HTML文档
        Elements links = doc.select("div.contson"); // 拿到所有诗词数组
        if (links.size() > 0) {
            String content = links.get(0).text();
            String respMessage = "<xml>\n" +
                    "  <ToUserName><![CDATA[" + to + "]]></ToUserName>\n" +
                    "  <FromUserName><![CDATA[" + from + "]]></FromUserName>\n" +
                    "  <CreateTime>" + cTime + "</CreateTime>\n" +
                    "  <MsgType><![CDATA[text]]></MsgType>\n" +
                    "  <Content><![CDATA[" + content + "]]></Content>\n" +
                    "</xml>";
            out.println(respMessage);
        }else {
            out.println("");
        }
    }

    /**
     * @param city    要查询天气所在城市
     * @param restCli Http请求对象
     * @param out     响应对象
     * @param from    公众号的微信号
     * @param to      发给谁，用户的OpenID
     * @throws JsonProcessingException
     */
    private void responseWeather(String city, RestTemplate restCli, PrintWriter out, String from, String to, String cTime) throws JsonProcessingException {
        String urlTemplate = "https://v0.yiketianqi.com/api?unescape=1&version=v91&appid=%s&appsecret=%s&ext=&cityid=&city=%s";

        //天气功能
        //1.2 获取天气的json数据
        String jsonStr = restCli.getForObject(String.format(urlTemplate, appId, secret, city), String.class);
        System.out.println("jsonStr:\n" + jsonStr);
        //2.1 解析Json数据
        ObjectMapper mapper = new ObjectMapper();
        Map<String, Object> jsonMap = mapper.readValue(jsonStr, new TypeReference<Map<String, Object>>() {
        });
        List<Object> dataList = (ArrayList<Object>) jsonMap.get("data");
        Map<String, Object> tempMap = (Map<String, Object>) dataList.get(0);
        String temp = String.valueOf(tempMap.get("tem"));

        String respMessage = "<xml>\n" +
                "  <ToUserName><![CDATA[" + to + "]]></ToUserName>\n" +
                "  <FromUserName><![CDATA[" + from + "]]></FromUserName>\n" +
                "  <CreateTime>" + cTime + "</CreateTime>\n" +
                "  <MsgType><![CDATA[text]]></MsgType>\n" +
                "  <Content><![CDATA[" + city + "当前的温度:" + temp + "]]></Content>\n" +
                "</xml>";

        out.println(respMessage);
    }

    /**
     * @param xmlStr
     * @return
     * @throws Exception Map<String,String>
     * @desc ： 解析微信发来的请求（XML）,获取请求参数
     */
    public static Map<String, String> parseXml(String xmlStr) throws Exception {
        // 将解析结果存储在HashMap中
        Map<String, String> map = new HashMap<String, String>();

        // 将字符串转为Document
        Document document = DocumentHelper.parseText(xmlStr);

        // 获取根元素的所有子节点
        // 得到xml根元素
        Element root = document.getRootElement();
        // 得到根元素的所有子节点
        List<Element> elementList = root.elements();
        // 遍历所有子节点
        for (Element e : elementList) {
            map.put(e.getName(), e.getText());
        }
        return map;
    }

}